﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web.Mvc;
using Vowei.Core;
using Vowei.Data;
using Vowei.Data.Models;
using Vowei.Data.Helpers;
using Vowei.Web.Models;
using Vowei.Web.Helpers;
using System.Collections;
using Vowei.Core.Models;
using System.Text;

namespace Vowei.Web.Controllers
{
    public class TicketControllerBase<T> : G18nController
        where T : Ticket, new()
    {
        protected IVoweiContext Context { get; private set; }
        protected IUser CurrentUser { get; private set; }

        public TicketControllerBase(IVoweiContext context, IUser user)
        {
            Context = context;
            CurrentUser = user;
        }

        public ActionResult CreateIn(Guid project)
        {
            return CreateInImpl(project);
        }

        protected ActionResult CreateInImpl(Guid projectId)
        {
            var ticket = EntityHelpers.GenericGetObjectDetails<T>(null, Context);
            if (!(ticket is IScoped))
                throw new InvalidOperationException(string.Format(T("要创建的工作类型 [{0}] 不需要指定范围，请使用Create函数创建！"), typeof(T)));

            dynamic query = null;

            var milestone = Context.Milestones.Find(projectId);

            if (milestone == null)
                throw new InvalidOperationException(string.Format(T("找不到id为 {0} 的项目!"), projectId));

            query = from m in milestone.AllMilestones(Context)
                    orderby m.DueDate
                    select new { m.ID, m.Title };

            var milestones = new ArrayList();
            milestones.Add(milestone);
            foreach (var o in query)
                milestones.Add(o);

            if (milestones.Count > 0)
            {
                ViewData["Milestones"] = ViewHelpers.SerializeToJson(milestones);
            }
            else
                ViewData["Milestones"] = ViewHelpers.SerializeToJson(new Milestone[] { (Milestone)milestone });

            ViewData["ProjectId"] = projectId;
            return View("Edit", ticket).AddJsonSupport();
        }

        public ActionResult Index(Guid? pid)
        {
            return IndexImpl(pid);
        }

        protected virtual ActionResult IndexImpl(Guid? pid)
        {
            if (pid == null)
            {
                return View(Context.Resolve<T>().Query.ToArray()).AddJsonSupport();
            }
            else
            {
                var project = Context.Milestones.Find(pid);

                if (project == null)
                    throw new InvalidOperationException(
                        string.Format(T("找不到ID为{0}的项目或里程碑"), pid));

                // TODO: 如果在Action之间转来转去，每个Action里都加一些东西，是不是会在
                // View里面产生很多的混乱？
                ViewData["Project"] = project;
                return View(project.AllTickets(Context).OfType<T>().ToArray()).AddJsonSupport();
            }
        }

        public ActionResult Active()
        {
            return ActiveImpl();
        }

        protected virtual ActionResult ActiveImpl()
        {
            var list = Context.Resolve<T>().Query.Active().ToArray();
            return View("Index", list).AddJsonSupport();
        }

        protected virtual List<T> ResortOfProxy(IEnumerable<T> table)
        {
            var result = new List<T>();

            foreach (var r in table)
            {
                result.Add(new T()
                {
                    ID = r.ID,
                    Title = r.Title,
                    AssignedTo = r.AssignedTo,
                    ClosedDate = r.ClosedDate,
                    Description = r.Description,
                    OpenDate = r.OpenDate,
                    Reporter = r.Reporter
                });
            }

            return result;
        }

        public ActionResult Json()
        {
            return JsonImpl(Context.Resolve<T>().Query.ToArray());
        }

        protected virtual ActionResult JsonImpl(IEnumerable<T> collection)
        {
            Response.Write(ViewHelpers.SerializeToJson(
                ResortOfProxy(collection)));

            return WebConstants.HttpSuccess;
        }

        public ActionResult My()
        {
            return MyImpl();
        }

        protected virtual ActionResult MyImpl()
        {
            var list = Context.Resolve<T>().Query.My(CurrentUser).Active().ToArray();
            return View("Index", list).AddJsonSupport();
        }

        public ActionResult Details(Guid id)
        {
            return DetailsImpl(id);
        }

        protected virtual ActionResult DetailsImpl(Guid id)
        {
            var ticket = EntityHelpers.GenericGetObjectDetails<T>(id, Context);

            // TODO: remove this if statement after test TicketBelongsToMilestoneForeignKeyTest is passed
            if (ticket.BelongsToMilestone == null)
                ticket.BelongsToMilestone = (Milestone)Context.Milestones.Find(ticket.BelongsToMilestoneId);

            var typeName = EntityHelpers.GetEntityTypeName(ticket.GetType());
            if (typeName == typeof(T).Name)
                return View(ticket);
            else
                return RedirectToAction("Details", typeName, new { id = id });
        }

        public ActionResult Create()
        {
            return CreateImpl();
        }

        protected virtual ActionResult CreateImpl()
        {
            return Edit((Guid?)null);
        }

        [HttpPost]
        [ValidateInput(false)]
        public ActionResult Create(T item)
        {
            item.OpenDate = DateTime.Now;
            item.Reporter = ViewHelpers.GetLogonUserName();
            return CreateImpl(item);
        }

        protected virtual ActionResult CreateImpl(T item)
        {
            return Edit(item);
        }

        public ActionResult Edit(Guid? id)
        {
            return EditImpl(id);
        }

        protected virtual ActionResult EditImpl(Guid? id)
        {
            return View("Edit", EntityHelpers.GenericGetObjectDetails<T>(id, Context)).AddJsonSupport();
        }

        [HttpPost]
        [ValidateInput(false)]
        public ActionResult Edit(T ticket)
        {
            return EditImpl(ticket);
        }

        protected virtual ActionResult EditImpl(T ticket)
        {
            EditingHelpers.GenericEndEdit(ticket, Context, CurrentUser);

            // TODO: 看看如何把这些小的补丁整合成一个通用的函数
            if (Request != null &&
                Request.AcceptTypes.Any(s => s == "application/json"))
            {
                var json = ViewHelpers.SerializeToJson(new
                {
                    ticket.ID,
                    ticket.Title
                });
                Response.Write(json);

                return WebConstants.HttpSuccess;
            }
            else
            {
                return RedirectToAction("Details", new { id = ticket.ID });
            }
        }

        public ActionResult ExportToExcel(string title, string reffer)
        {
            if ( reffer == null )
                reffer = Request.UrlReferrer.ToString();

            if (reffer == null)
                throw new InvalidOperationException(T("请不要直接访问ExportToExcel该动作！"));

            // TODO: 将直接往浏览器输出文件的功能封装成一个函数
            // 
            // StatisticsController.ExportProjectTasks这个函数也提供了直接打开文件的功能。
            var builder = new StringBuilder("WEB\r\n1\r\n");
            builder.Append(reffer);
            builder.Append("\r\n\r\n");
            builder.Append("Selection=");
            builder.Append(WebConstants.TicketsTableId);
            builder.Append("\r\nFormatting=None\r\n");
            builder.Append("PreFormattedTextToColumns=True\r\n");
            builder.Append("ConsecutiveDelimitersAsOne=True\r\n");
            builder.Append("SingleBlockTextImport=False\r\n");
            builder.Append("DisableDateRecognition=False\r\n");
            builder.Append("DisableRedirections=False");
            Response.ContentType = "text/x-ms-iqy";
            Response.Write(builder.ToString());

            if (title != null)
            {
                Response.AddHeader("Content-Disposition", string.Format("attachment;Filename={0}.iqy", title.Replace(' ', '-')));
            }

            return WebConstants.HttpSuccess;
        }
    }

    public class TicketController : TicketControllerBase<Ticket>
    {
        public TicketController(IVoweiContext context, IUser user) : base(context, user) { }
    }
}
